package com.zdya.combatdocuments.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zdya.combatdocuments.component.CombatDocumentConfig;
import com.zdya.combatdocuments.component.DocumentUtils;
import com.zdya.combatdocuments.constant.Constants;
import com.zdya.combatdocuments.entity.*;
import com.zdya.combatdocuments.entity.vo.DocumentVO;
import com.zdya.combatdocuments.entity.vo.UserChatVO;
import com.zdya.combatdocuments.ethereum.EthChain;
import com.zdya.combatdocuments.exception.BusinessException;
import com.zdya.combatdocuments.mapper.*;
import com.zdya.combatdocuments.p2pNetwork.NodeUtil;
import com.zdya.combatdocuments.service.UserChatService;
import com.zdya.combatdocuments.util.AjaxResult;
import com.zdya.combatdocuments.util.PDFSign;
import com.zdya.combatdocuments.util.PdfUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.net.*;
import java.nio.file.Paths;
import java.security.MessageDigest;
import java.util.*;

/**
 * @author bj
 * @date 23/6/1
 * @desc 用户聊天service
 */
@Slf4j
@Service
public class UserChatServiceImpl extends ServiceImpl<UserChatMapper, UserChat> implements UserChatService {

    @Value("${server.port}")
    private String port;
    @Autowired
    private NetworkUserMapper networkUserMapper;
    @Autowired
    private UserChatMapper userChatMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private DocumentMapper documentMapper;
    @Autowired
    private NodeUtil nodeUtil;
    @Autowired
    private DocumentUtils documentUtils;
    @Autowired
    private GradeMapper gradeMapper;

    private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();

    @Override
    @Transactional
    public UserChatVO sendMsg(MultipartFile multipartFile, UserChatVO userChatVO) {
        // 核实双方信息
        this.verifyInfo(userChatVO);
        if (!userChatVO.getType().equals(Constants.msg_type_2) && !userChatVO.getType().equals(Constants.msg_type_3)) {
            log.info("暂无法识别消息类型！");
            throw new BusinessException("暂无法识别消息类型！");
        }

        // 发送消息为图片或者普通文件
        if (userChatVO.getType().equals(Constants.msg_type_2) || userChatVO.getType().equals(Constants.msg_type_3)) {
            if (Objects.isNull(multipartFile)) {
                throw new BusinessException("文件发送失败！");
            }
            String uuId = IdUtil.fastSimpleUUID();
            String rootFilePath = documentUtils.storageFile(multipartFile, userChatVO.getType(), uuId);
            String originalFilename = multipartFile.getOriginalFilename();
            // 映射路径
            String relativePath = "";
            // 图片
            if (userChatVO.getType().equals(Constants.msg_type_2)) {
                relativePath = Constants.RESOURCE_PREFIX + Constants.PIC_PREFIX + uuId + "_" + originalFilename;
            }
            // 文件
            if (userChatVO.getType().equals(Constants.msg_type_3)) {
                relativePath = Constants.RESOURCE_PREFIX + Constants.FILE_PREFIX + uuId + "_" + originalFilename;
            }
            String[] toIds = userChatVO.getToId().split(",");
            List<String> errorIds = new ArrayList<String>();
            for(String toId : toIds){
                // 存储文件信息到数据库
                UserChat userChat = new UserChat();
                userChat.setOriginalFilename(originalFilename);// 文件原名
                userChat.setContent(relativePath);// 存储路径
                userChat.setType(userChatVO.getType()); // 消息类型
                userChat.setFromId(userChatVO.getFromId()); // 发送放id
                userChat.setToId(Long.valueOf(toId)); // 接收方id
                userChat.setNetId(nodeUtil.getNetworkId()); // 网络Id
                userChat.setCreateDate(System.currentTimeMillis());
                try {
                    if(nodeUtil.getWebSocketById(Long.valueOf(toId),nodeUtil.getIdToIpList()) == null){
                        errorIds.add(toId);
                    }else {
                        nodeUtil.writeFile(Long.valueOf(toId), rootFilePath, userChatVO.getType());
                        userChatMapper.insert(userChat);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if(errorIds.size()>0){
                String message = "";
                for(String id : errorIds){
                    String name = userMapper.selectById(id).getName();
                    message = message+" "+ name;
                }
                throw new BusinessException(message+"文件发送失败");
            }
            // 返回文件地址
            UserChatVO chatVO = new UserChatVO();
            String localAddr = this.getIpAddr(); //获得对应主机地址
            String serverPort = port; // 端口
            String filePath = Constants.HTTP + localAddr + ":" + serverPort + relativePath;
            chatVO.setContent(filePath);// 存储路径
            chatVO.setType(userChatVO.getType()); // 消息类型
            chatVO.setFromId(userChatVO.getFromId()); // 发送放id
            chatVO.setToId(userChatVO.getToId()); // 接收方id
            chatVO.setNetId(userChatVO.getNetId()); // 网络Id
            chatVO.setOriginalFilename(originalFilename);// 文件原名
            return chatVO;
        }
        return null;
    }

    /**
     * 文书呈报
     *
     * @param multipartFile
     * @param userChatVO
     * @return
     */
    @Override
    public UserChatVO declareDoc(MultipartFile multipartFile, UserChatVO userChatVO) {
        // 核实双方信息
        this.verifyInfo(userChatVO);
        // 呈报只能发送文件
        if (!userChatVO.getType().equals(Constants.msg_type_4)) {
            log.info("无法识别消息类型！");
            throw new BusinessException("无法识别消息类型！");
        }
        if (Objects.isNull(multipartFile)) {
            throw new BusinessException("文件发送失败！");
        }
        String serialNum = this.generateDocNo(userChatVO.getFromId());
        String originalFilename = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        if (!StrUtil.equals(suffix, ".doc") && !StrUtil.equals(suffix, ".docx") && !StrUtil.equals(suffix, ".pdf")) {
            throw new BusinessException("文书只允许word和pdf文件！");
        }
        // 如果是word转pdf
        String rootFilePath = "";
        Boolean wordFlag = false;
        String uuId = IdUtil.fastSimpleUUID();
        if (StrUtil.equals(suffix, ".doc") || StrUtil.equals(suffix, ".docx")) {
            try {
                InputStream inputStream = new ByteArrayInputStream(multipartFile.getBytes());

                byte[] bytes = PdfUtil.word2pdf(inputStream);
                ByteArrayInputStream inputByteStream = new ByteArrayInputStream(bytes);
                multipartFile = new MockMultipartFile(uuId + ".pdf", uuId + ".pdf", "application/pdf", inputByteStream);
                // 存储文书到本地
                Map<String, String> authenticationInfo = nodeUtil.getAuthenticationInfo();
                String authorMac = authenticationInfo.get("authorMac");
                String authorCpu = authenticationInfo.get("authorCpu");
                String authorName = authenticationInfo.get("authorName");
                String localMacAddress = authenticationInfo.get("localMacAddress");
                String localMacCpu = authenticationInfo.get("localCpu");
                String localName = authenticationInfo.get("localName");
                AuthorModel authorModel = new AuthorModel();
                authorModel.setAuthorName(authorName);
                authorModel.setAuthorMac(authorMac);
                authorModel.setAuthorCpu(authorCpu);
                authorModel.setSenderName(localName);
                authorModel.setSenderCpu(localMacCpu);
                authorModel.setSenderMacAddress(localMacAddress);

                JSONObject jsonObject = new JSONObject();
                jsonObject.put("authorModel", authorModel);
                nodeUtil.writePdfInfo(multipartFile, uuId, jsonObject.toString());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
                throw new BusinessException("格式转换异常！");
            }
            originalFilename = originalFilename.substring(0, originalFilename.lastIndexOf(".")) + ".pdf";
            rootFilePath = CombatDocumentConfig.getProfile() + Constants.DOC_PREFIX + uuId + ".pdf";
            wordFlag = true;
        }
        // 如果是PDF，直接存储到本地
        if (!wordFlag) {
            // 存储文书到本地
            Map<String, String> authenticationInfo = nodeUtil.getAuthenticationInfo();
            String authorMac = authenticationInfo.get("authorMac");
            String authorCpu = authenticationInfo.get("authorCpu");
            String authorName = authenticationInfo.get("authorName");
            String localMacAddress = authenticationInfo.get("localMacAddress");
            String localMacCpu = authenticationInfo.get("localCpu");
            String localName = authenticationInfo.get("localName");
            AuthorModel authorModel = new AuthorModel();
            authorModel.setAuthorName(authorName);
            authorModel.setAuthorMac(authorMac);
            authorModel.setAuthorCpu(authorCpu);
            authorModel.setSenderName(localName);
            authorModel.setSenderCpu(localMacCpu);
            authorModel.setSenderMacAddress(localMacAddress);
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("authorModel", authorModel);
            rootFilePath= nodeUtil.writePdfInfo(multipartFile, uuId, jsonObject.toString());
        }

        String[] toIds = userChatVO.getToId().split(",");

        List<String> toAccount = new ArrayList<>();
        for (int i = 0; i < toIds.length; i++) {
            User user = userMapper.selectById(toIds[i]);
            toAccount.add(user.getUsername());
        }
        userChatVO.setToAccount(toAccount);
        // 映射路径
        String docUrl = Constants.RESOURCE_PREFIX + Constants.DOC_PREFIX + uuId + ".pdf";
        String relativePath = Constants.HTTP + nodeUtil.getLocalIp() + ":"+nodeUtil.getServerPort() + Constants.RESOURCE_PREFIX + Constants.DOC_PREFIX + uuId + ".pdf";

        User user = userMapper.selectById(userChatVO.getFromId());
        User toUser = userMapper.selectById(toIds[0]);
        userChatVO.setSender(user.getUsername());
        // 存储到文书库表,每呈报一次文书记录表生成一条记录
        Document document = new Document();
        document.setFromName(user.getName());//发送方账号
        document.setToName(toUser.getName());//接收方账号
        document.setSerialNum(serialNum);// 文书编号
        document.setName(originalFilename);// 文书名称
        document.setType(userChatVO.getDocType());//类别 0 向上 1向下
        document.setContent(docUrl);// 存储地址
        document.setFromElement(user.getElement());//发送方要素
        document.setFromSeat(user.getSeat());//发送方席位
        document.setToElement(toUser.getElement());//发送方要素
        document.setToSeat(toUser.getSeat());//发送方席位
        document.setPath(rootFilePath);// 文书绝对地址 物理地址
        document.setStage(userChatVO.getStage());// 阶段
        document.setNetId(nodeUtil.getNetworkId());
        document.setStatus(0);// 状态：0-已备案；1-审批中；2-审批结束
        document.setCreateUser(userChatVO.getFromId());// 创建人
        document.setCreateDate(System.currentTimeMillis());// 当前时间戳
        document.setDocGrade(userChatVO.getDocGrade());// 等级
        try {
            documentMapper.insert(document);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
        // 存储文书信息到数据库 聊天记录表
        UserChat userChat = new UserChat();
        userChat.setSender(userChatVO.getSender());
        userChat.setToAccount(String.join(",",userChatVO.getToAccount()));
        userChat.setOriginalFilename(originalFilename);// 文书原名
        userChat.setContent(relativePath);// 存储路径
        userChat.setType(userChatVO.getType()); // 消息类型
        userChat.setSerialNum(serialNum);
        userChat.setFromId(userChatVO.getFromId()); // 发送放id
        userChat.setToId(toUser.getId()); // 接收方id
        userChat.setNetId(nodeUtil.getNetworkId()); // 网络Id
        userChat.setDocumentId(document.getId());
        userChat.setDocumentStatus("0");//文书状态 0 已发送 1 待处理 2 处理中 3 已处理 4 已完成
        userChat.setCreateDate(System.currentTimeMillis());// 時間
        try {
            userChatMapper.insert(userChat);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            throw new BusinessException("文书发送失败！");
        }
        LambdaQueryWrapper<Grade> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Grade::getNetworkId,nodeUtil.getNetworkId());
        wrapper.orderByAsc(Grade::getCreateDate);
        List<Grade> grades = gradeMapper.selectList(wrapper);
        int num = 1;
        for (int i = 0; i < grades.size(); i++) {
            Grade grade = grades.get(i);
            if(grade.getGradeName().equals(nodeUtil.getGrade().getGradeName())){
                num=i+1;
                break;
            }
        }
        // 上链
        Network network = nodeUtil.getLocalNetwork();
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("name", originalFilename);
        jsonObject.put("sender", user.getUsername());
        jsonObject.put("time", System.currentTimeMillis());
        jsonObject.put("status", 0);//审批状态
        jsonObject.put("sendTime", System.currentTimeMillis());
        jsonObject.put("stage", num+"");
        jsonObject.put("level", userChatVO.getDocGrade());// 文书等级
        jsonObject.put("type", userChatVO.getDocType());//向上、向下
        String value = Base64.getEncoder().encodeToString(jsonObject.toString().getBytes());
        Map<String, String> map = nodeUtil.map;
        AjaxResult allDataByChain = null;
        try {
            allDataByChain = EthChain.getAllDataByChain(network.getChainId(), network.getContract());
        } catch (Exception e) {
            e.printStackTrace();
        }
        if (allDataByChain != null && !"0".equals(allDataByChain.getCode())) {
            map = JSONUtil.toBean((String) allDataByChain.getData(), Map.class);
            Set<String> strings = map.keySet();
            for (String key : strings) {
                String s = map.get(key);
                s = new String(Base64.getDecoder().decode(s));
                map.put(key, s);
            }
        } else {
            map = new HashMap<>();
        }
        map.put(document.getSerialNum(), jsonObject.toString());
        nodeUtil.map = map;
        /**数据传至主节点保存*/
        nodeUtil.sendDataToPrimary(document.getSerialNum(),jsonObject);
        /**数据上链*/
        nodeUtil.threadPool.submit(() -> {
            try {
                AjaxResult ajaxResult = EthChain.uploadChain(network.getChainId(), network.getContract(), document.getSerialNum(), value);
                if("0".equals(ajaxResult.getCode())){
                    log.error(ajaxResult.getMessage());
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
//                throw new BusinessException("上链失败！");
            }
        });
        // 发送给对方审批
        userChatVO.getToAccount().remove(0);
        String success = "0";
        try {
            nodeUtil.writeFile(toUser.getId(), rootFilePath, userChatVO.getType(), userChat, document,userChatVO.getSender(),userChatVO.getToAccount());
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            success = "1";
        }
        if (success.equals("1")) {
            userChat.setSuccess(success);
            try {
                userChatMapper.updateById(userChat);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            throw new BusinessException("消息发送失败！");
        }
        // 返回文件地址
        UserChatVO chatVO = new UserChatVO();
        chatVO.setContent(relativePath);
        chatVO.setId(document.getId());
        chatVO.setOriginalFilename(originalFilename);
        return chatVO;
    }

    /**
     * @param userChatVO 传参信息
     * @return
     * @desc 文书审批
     */
    @Override
    public UserChatVO approveDoc(UserChatVO userChatVO) {
        // 核实双方信息
        this.verifyInfo(userChatVO);
        // 审批只能发送文件
        if (!userChatVO.getType().equals(Constants.msg_type_4)) {
            log.info("暂无法识别消息类型！");
            throw new BusinessException("暂无法识别消息类型！");
        }
        // 文书编号
        String serialNum = userChatVO.getSerialNum();
        Document document = null;
        // 查询当前编号最新的文书版本
        try {
            LambdaQueryWrapper<Document> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(serialNum != null, Document::getSerialNum, serialNum);
            wrapper.orderByDesc(Document::getCreateDate);
            List<Document> documents = documentMapper.selectList(wrapper);
            document = documents.get(0);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("暂未查询到此文书信息！");
        }
        byte[] bytes = FileUtil.readBytes(document.getPath());
        // 获取文书原名
        String originalFilename = Paths.get(document.getPath()).getFileName().toString();
        // 获取文件后缀
        String suffix = originalFilename.substring(originalFilename.lastIndexOf("."));
        if (!StrUtil.equals(suffix, ".pdf")) {
            throw new BusinessException("审批只能回传pdf文件！");
        }
        // 存储文书到本地
        String uuId = IdUtil.fastSimpleUUID();
        String rootFilePath = CombatDocumentConfig.getProfile() + Constants.DOC_PREFIX + uuId + ".pdf";
        // 给PDF添加签章
        try {
            // 图片
            List<Image> images = userChatVO.getList();
            byte[] pdfs = bytes;
            pdfs = PDFSign.PicturePDF(pdfs, images);
            // 存储文书到本地
            ByteArrayInputStream inputStream = new ByteArrayInputStream(pdfs);
            MultipartFile multipartFile = new MockMultipartFile(uuId + ".pdf", uuId + ".pdf", "application/pdf", inputStream);
            // 获取已存在鉴权信息
            String authorization = nodeUtil.readPdfInfo(multipartFile);
            com.alibaba.fastjson.JSONObject jsonObject = com.alibaba.fastjson.JSONObject.parseObject(authorization);
            List<LocalModel> list = new ArrayList<>();
            if (!Objects.isNull(jsonObject.get("list"))) {
                list = (List<LocalModel>) jsonObject.get("list");
            }
            // 把当前审批人信息写入鉴权信息
            LocalModel localModel = new LocalModel();
            Map<String, String> authenticationInfo = nodeUtil.getAuthenticationInfo();
            String localMacAddress = authenticationInfo.get("localMacAddress");
            String localCpu = authenticationInfo.get("localCpu");
            String localName = authenticationInfo.get("localName");
            localModel.setLocalName(localName);
            localModel.setLocalCpu(localCpu);
            localModel.setLocalMacAddress(localMacAddress);
            list.add(localModel);
            jsonObject.put("list", list);
            nodeUtil.writePdfInfo(multipartFile, uuId, jsonObject.toString());
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("审批失败！");
        }
        // 映射路径
        String docUrl = Constants.RESOURCE_PREFIX + Constants.DOC_PREFIX + uuId + ".pdf";;
        String relativePath = Constants.HTTP + nodeUtil.getLocalIp() + ":"+nodeUtil.getServerPort() + Constants.RESOURCE_PREFIX + Constants.DOC_PREFIX + uuId + ".pdf";
        User user = userMapper.selectById(userChatVO.getFromId());

        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        if (userChatVO.getToAccount() == null || userChatVO.getToAccount().size() == 0 ||userChatVO.getToAccount().get(0).equals("")) {
            wrapper.eq(User::getUsername, userChatVO.getSender());
        } else {
            wrapper.eq(User::getUsername, userChatVO.getToAccount().get(0));
        }
        User toUser = userMapper.selectOne(wrapper);
        // 文书表新增一条记录
        document.setSerialNum(userChatVO.getSerialNum());// 文书编号
        document.setName(document.getName());// 文书名称
        document.setType(document.getType());//类别 0 向上 1向下
        document.setFromName(user.getName());//发送方账号
        document.setToName(toUser.getName());//接收方账号
        document.setFromElement(user.getElement());//发送方要素
        document.setFromSeat(user.getSeat());//发送方席位
        document.setToElement(toUser.getElement());//发送方要素
        document.setToSeat(toUser.getSeat());//发送方席位
        document.setContent(docUrl);// 存储地址
        document.setPath(rootFilePath);// 文书地址，物理地址
        document.setStage(userChatVO.getStage());// 阶段
        document.setNetId(nodeUtil.getNetworkId());
        document.setStatus(1);// 状态：0-未审批；1-审批中；2-审批结束
        document.setCreateUser(userChatVO.getFromId());// 创建者
        document.setCreateDate(System.currentTimeMillis());// 时间
        document.setDocGrade(document.getDocGrade());// 等级
        try {
            documentMapper.insert(document);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }

        // 存储文书信息到数据库 聊天记录表
        UserChat userChat = new UserChat();
        userChat.setSender(userChatVO.getSender());
        if(userChatVO.getToAccount()== null){
            userChat.setToAccount(null);
        }else {
            userChat.setToAccount(String.join(",",userChatVO.getToAccount()));
        }
        userChat.setOriginalFilename(document.getName());// 文书原名
        userChat.setContent(relativePath);// 存储路径
        userChat.setType(userChatVO.getType()); // 消息类型
        userChat.setSerialNum(userChatVO.getSerialNum());
        userChat.setFromId(userChatVO.getFromId()); // 发送放id
        userChat.setDocumentId(document.getId());
        userChat.setToId(toUser.getId()); // 接收方id
        userChat.setNetId(nodeUtil.getNetworkId()); // 网络Id
        userChat.setDocumentStatus("3");//文书状态 0 已发送 1 待处理 2 处理中 3 已处理 4 已完成
        userChat.setForward("2");//转发状态 0 否 1 是 2 回传
        userChat.setCreateDate(System.currentTimeMillis());
        try {
            userChatMapper.insert(userChat);
            List<UserChat> userChats = userChatMapper.selectList(new LambdaQueryWrapper<UserChat>().eq(UserChat::getSerialNum, userChat.getSerialNum())
                    .eq(UserChat::getDocumentStatus, "1"));
            if(userChats !=null){
                for(UserChat chat:userChats){
                    chat.setDocumentStatus("3");
                    userChatMapper.updateById(chat);
                }
            }
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            throw new BusinessException("文书发送失败！");
        }

        // 审批完成，上链之后，转发给下一个
        if (userChatVO.getToAccount() !=null && userChatVO.getToAccount().size() > 0) {
            userChatVO.getToAccount().remove(0);
        }
        String success = "0";
        try {
            if(userChatVO.getToAccount() ==null || userChatVO.getToAccount().size() == 0){
                nodeUtil.writeFile(toUser.getId(), rootFilePath, userChatVO.getType(), userChat, document,userChatVO.getSender(), null);
            }else {
                nodeUtil.writeFile(toUser.getId(), rootFilePath, userChatVO.getType(), userChat, document,userChatVO.getSender(), userChatVO.getToAccount());
            }

        } catch (Exception e) {
            log.info(e.getMessage(), e);
            success = "1";
        }
        // 消息发送失败，更新聊天记录
        if (success.equals("1")) {
            userChat.setSuccess(success);
            try {
                userChatMapper.updateById(userChat);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            throw new BusinessException("消息发送失败！");
        }
        // 返回文件地址
        UserChatVO chatVO = new UserChatVO();
        chatVO.setContent(relativePath);
        return chatVO;
    }

    /**
     * @param documentVO
     * @return
     * @desc 查看文书详情
     */
    @Override
    public DocumentVO viewDocDetail(DocumentVO documentVO) {
        // 文书id为空
        try {
            Long docId = null;
            if (Objects.isNull(documentVO.getId())) {
                docId = documentVO.getDocumentId();
            } else {
                docId = documentVO.getId();
            }
            // 根据id查询文书信息
            Document document = null;
            try {
                document = documentMapper.selectById(docId);
            } catch (Exception e) {
                log.info(e.getMessage(), e);
                throw new BusinessException("文书信息异常！");
            }
            DocumentVO documentVOInfo = new DocumentVO();
            List<ChainData> chainDataList = nodeUtil.getChainDataList();
            for (ChainData chainData : chainDataList) {
                if (Objects.isNull(chainData.getSerialNum())) {
                    continue;
                }
                if (chainData.getSerialNum().equals(document.getSerialNum())) {
                    documentVOInfo.setSerialNum(chainData.getSerialNum());// 文书编号
                    documentVOInfo.setName(chainData.getOriginalFileName());// 文书名称
                    documentVOInfo.setDocGrade(chainData.getLevel());// 文书等级
                    documentVOInfo.setType(chainData.getType());// 文书类别 0 向上 1 向下
                    documentVOInfo.setCreateDate(chainData.getSendTime());
                    String signs = chainData.getSigns();
                    List<Sign> list = new ArrayList<>();
                    List<Sign> lists = new ArrayList<>();
                    if (StrUtil.isNotBlank(signs)) {
                        list = JSONUtil.parseArray(signs).toList(Sign.class);
                    }
                    Sign sign = new Sign();
                    LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(User::getUsername, chainData.getSender());
                    User sender = userMapper.selectOne(wrapper);
                    sign.setName(sender.getName());
                    sign.setTime(chainData.getSendTime());
                    sign.setTimeout(false);
                    lists.add(sign);
                    if (!Objects.isNull(list)) {
                        for (Sign s : list) {
                            lists.add(s);
                        }
                    }
                    documentVOInfo.setSigns(lists);
                }
            }
            return documentVOInfo;
        }catch (Exception e){
            return null;
        }
    }


    /**
     * @param userChatVO
     * @return
     * @desc 查询用户聊天记录
     */
    @Override
    public UserChatVO queryUserChats(UserChatVO userChatVO) {
        if (Objects.isNull(userChatVO.getFromId()) || Objects.isNull(userChatVO.getToId())) {
            throw new BusinessException("缺少必输字段！");
        }
        // 查询最新50条聊天记录
        LambdaQueryWrapper<UserChat> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(UserChat::getNetId, nodeUtil.getNetworkId());
        wrapper.in(UserChat::getFromId, userChatVO.getToId(), userChatVO.getFromId());
        wrapper.in(UserChat::getToId, userChatVO.getToId(), userChatVO.getFromId());
        wrapper.orderByDesc(UserChat::getId);
        wrapper.last("limit 50");
        List<UserChat> userChats = new ArrayList<>();
        try {
            userChats = userChatMapper.selectList(wrapper);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
        userChats.sort((a,b) -> (int) (a.getId() - b.getId()));
        UserChatVO userChat = new UserChatVO();
        userChat.setUserChatList(userChats);
        return userChat;
    }

    /**
     * 文书审批结束，状态更新
     *
     * @param chatId
     * @param docId
     */
    @Override
    public void updateDocEndStatus(Long chatId, Long docId) {
        if (Objects.isNull(chatId) || Objects.isNull(docId)) {
            throw new BusinessException("缺少必输字段！");
        }
        try {
            // 文书库查询文书记录
            Document document = documentMapper.selectById(docId);
            String serialNum = document.getSerialNum();
            LambdaQueryWrapper<UserChat> userChatWrapper = new LambdaQueryWrapper<>();
            userChatWrapper.eq(UserChat::getSerialNum, serialNum);
            userChatWrapper.orderByDesc(UserChat::getId);
            userChatWrapper.last("limit 1");
            UserChat userChatInfo = userChatMapper.selectOne(userChatWrapper);
            Long fromId = userChatInfo.getFromId();
            User user = userMapper.selectById(fromId);
            String username = user.getName();
            Network network = nodeUtil.getLocalNetwork();
//            // 审批完成上链
//            Network network = nodeUtil.getLocalNetwork();
//            AjaxResult dataByChain = EthChain.getDataByChain(network.getChainId(), network.getContract(), null, null, document.getSerialNum());
//            String data = dataByChain.getData().toString();
//            if (StrUtil.isBlank(data)) {
//                throw new BusinessException("链上数据暂未更新，请稍后再试！");
//            }

            ChainData result = null;
            for (ChainData chainData : nodeUtil.getChainDataList()) {
                if (chainData.getSerialNum().equals(serialNum) || chainData.getSerialNum() == serialNum) {
                    result = chainData;
                }
            }
            JSONObject jsonObject = JSONUtil.parseObj(result);
            Object signs1 = jsonObject.get("signs");
            if (Objects.isNull(signs1)) {
                throw new BusinessException("链上数据暂未更新，请稍后再试！");
            }
            List<Sign> signs = JSONUtil.parseArray(signs1).toList(Sign.class);
            Sign signModel = signs.get(signs.size() - 1);
            if (!signModel.getName().equals(username)) {
                throw new BusinessException("链上数据暂未更新，请稍后再试！");
            }
            jsonObject.put("time", System.currentTimeMillis());
            jsonObject.put("status", 2);
            nodeUtil.updateDataToPrimary(document.getSerialNum(),jsonObject);
            String value = Base64.getEncoder().encodeToString(jsonObject.toString().getBytes());
            try {
                AjaxResult ajaxResult = EthChain.updateChain(network.getChainId(), network.getContract(), document.getSerialNum(), value);
                if("0".equals(ajaxResult.getCode())){
                    log.error(ajaxResult.getMessage());
                }
            } catch (Exception e) {
                log.error(e.getMessage(), e);
//                throw new BusinessException("上链失败！");
            }

            // 更新聊天记录中文书状态
            LambdaQueryWrapper<UserChat> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(UserChat::getId, chatId);
            wrapper.orderByDesc(UserChat::getCreateDate);
            wrapper.last("limit 1");
            UserChat userChat = userChatMapper.selectOne(wrapper);
            userChat.setDocumentStatus("4");//已完成
            userChat.setCreateDate(System.currentTimeMillis());
            userChatMapper.updateById(userChat);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }


    /**
     * 文件转发
     *
     * @param userChatVO
     * @return
     */
    @Override
    public UserChatVO docForward(UserChatVO userChatVO) {
        userChatVO.setSender(nodeUtil.getLocalUser().getUsername());
        String docAccessPath = userChatVO.getDocAccessPath();
        URL url = null;
        URI uri = null;
        try {
            url = new URL(docAccessPath);
            uri = url.toURI();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
        String originalFilename = uri.getPath().split("/")[uri.getPath().split("/").length - 1];
        String uuId = IdUtil.fastSimpleUUID();
        // 映射路径
        String docUrl = Constants.RESOURCE_PREFIX + Constants.DOC_PREFIX + uuId + ".pdf";
        String relativePath = Constants.HTTP + nodeUtil.getLocalIp() + ":"+nodeUtil.getServerPort() + Constants.RESOURCE_PREFIX + Constants.DOC_PREFIX + uuId + ".pdf";;
        // 获取文件绝对路径
        String rootFilePath = CombatDocumentConfig.getProfile() + Constants.DOC_PREFIX + originalFilename;
        byte[] bytes = FileUtil.readBytes(rootFilePath);
        // 把读取的文件存储为新的文件
        rootFilePath = CombatDocumentConfig.getProfile() + Constants.DOC_PREFIX + uuId + ".pdf";
        FileUtil.writeBytes(bytes, rootFilePath);
        String[] toIds = userChatVO.getToId().split(",");
        List<String> toAccount = new ArrayList<>();
        for (int i = 0; i < toIds.length; i++) {
            User user = userMapper.selectById(toIds[i]);
            toAccount.add(user.getUsername());
        }
        userChatVO.setToAccount(toAccount);

        User user = userMapper.selectById(userChatVO.getFromId());
        User toUser = userMapper.selectById(toIds[0]);
        // 存储到文书库表
        // 每呈报一次文书记录表生成一条记录
        Document document = new Document();
        document.setFromName(user.getName());//发送方账号
        document.setToName(toUser.getName());//接收方账号
        document.setSerialNum(userChatVO.getSerialNum());// 文书编号
        document.setName(userChatVO.getOriginalFilename());// 文书名称
        document.setContent(docUrl);// 存储地址
        document.setFromElement(user.getElement());//发送方要素
        document.setFromSeat(user.getSeat());//发送方席位
        document.setToElement(toUser.getElement());//发送方要素
        document.setToSeat(toUser.getSeat());//发送方席位
        document.setPath(rootFilePath);// 文书绝对地址
        document.setNetId(nodeUtil.getNetworkId());
        document.setStage(userChatVO.getStage());// 阶段
        document.setStatus(1);// 状态：0-未审批；1-审批中；2-审批结束
        document.setCreateUser(userChatVO.getFromId());// 创建人
        document.setCreateDate(System.currentTimeMillis());// 当前时间戳
        /**通过审批流查询当前的等级*/
        LambdaQueryWrapper<Document> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Document::getSerialNum,userChatVO.getSerialNum());
        List<Document> documents = documentMapper.selectList(wrapper);
        document.setDocGrade(documents.get(0).getDocGrade());
        document.setType(documents.get(0).getType());//类别 0 向上 1向下
        try {
            documentMapper.insert(document);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }

        // 存储文书信息到数据库 聊天记录表
        UserChat userChat = new UserChat();
        userChat.setSender(userChatVO.getSender());
        userChat.setToAccount(String.join(",",userChatVO.getToAccount()));
        userChat.setOriginalFilename(userChatVO.getOriginalFilename());// 文书原名
        userChat.setContent(relativePath);// 存储路径
        userChat.setSerialNum(userChatVO.getSerialNum());
        userChat.setType(userChatVO.getType()); // 消息类型
        userChat.setDocumentId(document.getId());
        userChat.setFromId(userChatVO.getFromId()); // 发送放id
        userChat.setToId(toUser.getId()); // 接收方id
        userChat.setNetId(nodeUtil.getNetworkId()); // 网络Id
        userChat.setDocumentStatus("0");//文书状态 0 已发送 1 待处理 2 处理中 3 已处理 4 已完成
        userChat.setCreateDate(System.currentTimeMillis());
        try {
            List<UserChat> userChats = userChatMapper.selectList(new LambdaQueryWrapper<UserChat>().eq(UserChat::getSerialNum, userChat.getSerialNum())
                    .eq(UserChat::getDocumentStatus, "2"));
            if(userChats !=null){
                for(UserChat chat:userChats){
                    chat.setDocumentStatus("3");
                    userChatMapper.updateById(chat);
                }
            }
            userChatMapper.insert(userChat);
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            throw new BusinessException("文书发送失败！");
        }
        // 转发之前，移除当前用户
        userChatVO.getToAccount().remove(0);
        // 发送给对方审批
        String success = "0";
        try {
            nodeUtil.writeFile(toUser.getId(), rootFilePath, userChatVO.getType(), userChat, document,userChatVO.getSender(), userChatVO.getToAccount());
        } catch (Exception e) {
            log.info(e.getMessage(), e);
            success = "1";
        }
        if (success.equals("1")) {
            userChat.setSuccess(success);
            try {
                userChatMapper.updateById(userChat);
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
            throw new BusinessException("消息发送失败！");
        }

        // 返回文件地址
        UserChatVO chatVO = new UserChatVO();
        chatVO.setContent(relativePath);
        return chatVO;
    }


    // 核实通讯双方信息
    private void verifyInfo(UserChatVO userChatVO) {
        // 校验发送方id/接收方id
        if (Objects.isNull(userChatVO.getFromId()) || Objects.isNull(userChatVO.getToId())) {
            throw new BusinessException("暂无法发送消息！");
        }
        // 消息类型不能为空
        if (Objects.isNull(userChatVO.getType())) {
            throw new BusinessException("消息类型不能为空！");
        }
        NetworkUser networkUserFrom = null;
        NetworkUser networkUserTo = null;
        try {
            // 查询自己是否在这个网络内
            LambdaQueryWrapper<NetworkUser> wrapperFrom = new LambdaQueryWrapper();
            wrapperFrom.eq(NetworkUser::getUserId, userChatVO.getFromId());
            wrapperFrom.eq(NetworkUser::getNetworkId, nodeUtil.getNetworkId());
            networkUserFrom = networkUserMapper.selectOne(wrapperFrom);
            // 查询对方是否在这个网络内
            LambdaQueryWrapper<NetworkUser> wrapperTo = new LambdaQueryWrapper();
            wrapperTo.eq(NetworkUser::getUserId, userChatVO.getToId());
            wrapperTo.eq(NetworkUser::getNetworkId, nodeUtil.getNetworkId());
            networkUserTo = networkUserMapper.selectOne(wrapperTo);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("通讯异常！");
        }

        // 判断和对方是否同处于一个网络
        if (!Objects.isNull(networkUserFrom) && !Objects.isNull(networkUserTo)) {
            if (!Objects.equals(networkUserFrom.getNetworkId(), networkUserTo.getNetworkId())) {
                throw new BusinessException("您和对方不处于同一网络");
            }
            // 网络id
            userChatVO.setNetId(networkUserFrom.getNetworkId());
        }
    }

    /**
     * @return
     * @desc 获取ip和端口号
     */
    private String getIpAddr() {
        String os = System.getProperty("os.name");
        if (os != null && os.startsWith("Windows")) {
            List<String> gateways = getGatewayIPs();
            for (String gateway : gateways) {
                log.info("Default Gateway IP: " + gateway);
                return gateway;
            }
        } else if (os != null && os.startsWith("Linux")) {
            List<String> gateways = getGatewayIPs();
            for (String gateway : gateways) {
                log.info("Default Gateway IP: " + gateway);
                return gateway;
            }
        } else {
            throw new BusinessException("Unknow operating system:" + os);
        }
        return null;
    }

    public static List<String> getGatewayIPs() {
        List<String> gateways = new ArrayList<>();
        try {
            Enumeration<NetworkInterface> networkInterfaces = NetworkInterface.getNetworkInterfaces();
            while (networkInterfaces.hasMoreElements()) {
                NetworkInterface networkInterface = networkInterfaces.nextElement();
                if (!networkInterface.isLoopback() && networkInterface.isUp()) {
                    List<String> interfaceAddresses = getInterfaceAddresses(networkInterface);
                    if (!interfaceAddresses.isEmpty()) {
                        gateways.add(interfaceAddresses.get(0)); // 获取第一个IP地址作为默认网关IP
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException("获取默认网关ip异常！");
        }
        return gateways;
    }

    private static List<String> getInterfaceAddresses(NetworkInterface networkInterface) {
        List<String> addresses = new ArrayList<>();
        Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
        while (inetAddresses.hasMoreElements()) {
            InetAddress inetAddress = inetAddresses.nextElement();
            if (inetAddress instanceof Inet4Address) { // 只获取IPv4地址
                addresses.add(inetAddress.getHostAddress());
            }
        }
        return addresses;
    }

    /**
     * 根据发送方Id和时间戳生成文书编号文书编号
     *
     * @param fromId 发送方Id
     * @return
     */
    private String generateDocNo(Long fromId) {
        long millis = System.currentTimeMillis();
        String message = millis + "_" + fromId;
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            byte[] hash = md.digest(message.getBytes());
            String hex = bytesToHex(hash);
            return hex;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new BusinessException(e.getMessage());
        }
    }

    private static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for (int i = 0; i < bytes.length; i++) {
            int v = bytes[i] & 0xFF;
            hexChars[i * 2] = HEX_ARRAY[v >>> 4];
            hexChars[i * 2 + 1] = HEX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

}
